// Board.h
//
// Created By: Jeremy Butler
// Created On: 21-Mar-2011
//
// This class represents a chess board and all of the chess pieces on it.
// It has 8 Rows of 8 Spaces each which are 64 Spaces total. With the top left
// Space at index [0][0] and the bottom right Space at index [7][7].
//
// Note that the board stores copies of the pieces added to it.
// The user is not responsible for deleting these pieces.

#ifndef BOARD_H
#define BOARD_H

#include "CS240Exception.h"
#include "ChessUtils.h"

#include <vector>
using namespace std;

class Board {
private:
  Piece * spaces[8][8]; // An 8 x 8 board of spaces
  set<Piece *> whitePieces;
  set<Piece *> blackPieces;
  Location whiteKingLocation;
  Location blackKingLocation;

public:
  //! @brief No-Arg Constructor
  Board();

  //! @brief Copy Constructor
  //! @param other The Board to be copied.
  Board(const Board & other);

  //! @brief Constructor
  //! @param pieces The pieces to initialize the board with.
  //Board(const set<Piece> & pieces);

  //! @brief Destructor
  ~Board();

  //! @brief operator = used to copy another Board to this Board
  //! @param other the Board to be copied.
  //! @return a reference to the newly copied Board.
  Board & operator = (const Board & other);

  //! @brief Operator () used to reference a piece on the board
  //! @param row the row of the piece to be referenced.
  //! @param col the column of the piece to be referenced.
  //! @return a pointer to the Piece at (row,col)
  //! @throws InvalidArgumentException if row or col < 0 or > 7.
  //Piece * & operator() (unsigned row, unsigned col);

  //! @brief Operator () used to reference a piece on the board
  //! @param row the row of the piece to be referenced.
  //! @param col the column of the piece to be referenced.
  //! @return a pointer to the Piece at (row,col)
  //! @throws InvalidArgumentException if row or col < 0 or > 7.
  const Piece * operator() (int row, int col) const;

  //! @brief move a piece from 'from' to 'to'
  //! @param fromRow The current row of the Piece to move.
  //! @param fromCol The current column of the Piece to move.
  //! @param toRow The row to move the Piece to.
  //! @param toCol The column to move the Piece to.
  void MovePiece(int fromRow, int fromCol, int toRow, int toCol, PieceType newPieceType = NO_TYPE);

  //should just be able to use [][]
  //! @brief Get a pointer to a Piece in a Space
  //! @param location the Location of the Piece to get.
  //! @return a pointer to the Piece in the Space or NULL if there is not a Piece in the Space;
  //const Piece * GetPiece(const Location & location) const;

  //! @brief Remove a Piece from the Board
  //! @param row the row the Piece is in.
  //! @param col the column that the Piece is in.
  void RemovePiece(int row, int col);

  //! @brief Add a piece to the board
  //! @param piece the piece to be added.
  //! @param location the location to place the piece on the board.
  //!
  //! Note that if a piece is already at (row,col) then it will be replaced by
  //! the piece passed into this function.
  void AddPiece(const Piece & piece, int row, int col);

  //! @brief Get a set of Locations of the valid moves of a piece
  //! @param row the row number of the Piece (0-7)
  //! @param col the column number of the Piece (0-7)
  //! @return a set of Locations of the valid moves of the piece at location [row][col]
  //!
  //! Note that if there is no piece at [row][col], then an empty set will be returned.
  set<Location> GetValidMoves(int row, int col) const;

  bool IsInCheck(Color color) const;

  //! This should only be called after IsInCheck()
  //! to ensure that it is really checkmate and not stalemate.
  bool IsInCheckMate(Color color) const;

  bool IsStaleMate(Color currentColor) const;

  void Clear();

  void RemoveCheckMoves(set< Location >& moves, int fromRow, int fromCol) const;

  const set<Piece *> & GetPieces(Color color) const;

  const Location GetPieceLocation(const Piece * piece) const;
  
private:
  void Copy(const Board & other);
  void Init();
  bool CheckSameTypeInMoves(const set<Location> & moves, const Piece * piece) const;
  bool HaveNoMovesLeft(Color color) const;
  bool InCheckByPawn(Color color, int kingRow, int kingCol) const;
  bool InCheckByRook(Color color, int kingRow, int kingCol) const;
  bool InCheckByKnight(Color color, int kingRow, int kingCol) const;
  bool InCheckByBishop(Color color, int kingRow, int kingCol) const;
  bool InCheckByQueen(Color color, int kingRow, int kingCol) const;
  bool InCheckByKing(Color color, int kingRow, int kingCol) const;
};

#endif /* BOARD_H */
  